#ifndef __THREAD_H__
#define __THREAD_H__

#include <pthread.h>
#include <assert.h>

class Thread;
class Runnable
{
public:
    virtual ~Runnable(){}
    virtual void run(Thread * thread, void * arg) = 0;
};

class Thread
{
public:
    Thread() {_tid = 0;}
    ~Thread() {}

    void start(Runnable * runnable, void * arg)
    {
        _runnable = runnable;
        _arg = arg;
        pthread_create(&_tid, NULL, Thread::hook, this);
    }

    void join()
    {
        if (_tid > 0) {
            pthread_join(_tid, NULL);
        }
    }

    Runnable * getRunnable()
    {
        return _runnable;
    }

    void * getArg()
    {
        return _arg;
    }

    static void * hook(void * opt)
    {
        Thread * thread = (Thread *)opt;
        if (thread->getRunnable()) {
            thread->getRunnable()->run(thread, thread->getArg());
        }
        return opt;
    }

private:
    pthread_t _tid;
    Runnable * _runnable;
    void * _arg;
};

class ThreadMutex
{
public:
    ThreadMutex()
    {
        int ret = pthread_mutex_init(&_mutex, NULL);
        assert(ret == 0);
    }
    ~ThreadMutex()
    {
        pthread_mutex_destroy(&_mutex);
    }
    void lock()
    {
        pthread_mutex_lock(&_mutex);
    }
    void unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }
protected:
    pthread_mutex_t _mutex;
};

class ScopeLock
{
public:
    ScopeLock(ThreadMutex * mutex)
    {
        _mutex = mutex;
        if (_mutex) {
            _mutex->lock();
        }
    }
    ~ScopeLock()
    {
        if (_mutex) {
            _mutex->unlock();
        }
    }
private:
    ThreadMutex * _mutex;
};

#endif
